'****************************************************************************'
'                                                                            '
' Copyright (C) 2010 Muhammad alaa                                           '
'                                                                            '
' This program is free software; you can redistribute it and/or modify       '
' it under the terms of the GNU General Public License as published by       '
' the Free Software Foundation; either version 2 of the License, or          '
' (at your option) any later version.                                        '
'                                                                            '
' This program is distributed in the hope that it will be useful,            '
' but WITHOUT ANY WARRANTY; without even the implied warranty of             '
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              '
' GNU General Public License for more details.                               '
'                                                                            '
' You should have received a copy of the GNU General Public License along    '
' with this program; if not, write to the Free Software Foundation, Inc.,    '
' 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.                '
'                                                                            '
'****************************************************************************'

Imports System.Reflection

Namespace DataTypes

    ''' <summary>
    ''' message group
    ''' </summary>
    Public Enum MessageType
        ''' <summary>
        ''' System pre-defined WM_* Message in Range 0h to 3FFh and above FFFFh
        ''' </summary>
        SystemDefined = 0
        ''' <summary>
        ''' System Pre-defined Control Messages in Range 400h to 7FFFh
        ''' </summary>
        WindowClass = 1
        ''' <summary>
        ''' Application Registred Messages in Range 8000h to BFFFh
        ''' </summary>
        ApplicationDefined = 2
        ''' <summary>
        ''' String Message in Range C000h to FFFFh
        ''' </summary>
        StringMesage = 3
    End Enum

    ''' <summary>
    ''' represent a message defination
    ''' </summary>
    Public NotInheritable Class MessageDef
        Private mCode As UInteger
        Private mName() As String

        ''' <summary>
        ''' initialize new instance of MessageDef
        ''' </summary>
        ''' <param name="Code">message code</param>
        Public Sub New(ByVal Code As UInteger)
            mCode = Code
            mName = GetName(Code, Type)
        End Sub

        ''' <summary>
        ''' get message name with index
        ''' </summary>
        ''' <param name="Index">index of name</param>
        Default Public ReadOnly Property Name(ByVal Index As Integer) As String
            Get
                If mName IsNot Nothing Then Return mName(Index)

                Return String.Empty
            End Get
        End Property

        ''' <summary>
        ''' number of names for current message
        ''' </summary>
        Public ReadOnly Property Count() As Integer
            Get
                If mName IsNot Nothing Then Return mName.Length

                Return 0
            End Get
        End Property

        ''' <summary>
        ''' get message type
        ''' </summary>
        Public ReadOnly Property Type() As MessageType
            Get
                If (mCode >= 0 AndAlso mCode <= &H3FF) OrElse mCode > &HFFFF Then
                    Return MessageType.SystemDefined

                ElseIf mCode >= &H400 AndAlso mCode <= &H7FFF Then
                    Return MessageType.WindowClass

                ElseIf mCode >= &H8000 AndAlso mCode <= &HBFFF Then
                    Return MessageType.ApplicationDefined
                Else
                    Return MessageType.StringMesage
                End If
            End Get
        End Property

        Public Shared Widening Operator CType(ByVal Code As UInteger) As MessageDef
            Return New MessageDef(Code)
        End Operator

        Public Shared Narrowing Operator CType(ByVal Obj As MessageDef) As UInteger
            Return Obj.mCode
        End Operator

        ''' <summary>
        ''' get name of message using its code and its category
        ''' </summary>
        ''' <param name="Code">Message code</param>
        ''' <param name="mt">Message Type</param>
        ''' <returns>return array of message names, Null otherwise</returns>
        Private Shared Function GetName(ByVal Code As UInteger, ByVal mt As MessageType) As String()
            ' hold temporary class type
            Dim t As Type = Nothing

            ' if message type is system or window class
            ' so we'll search in classes
            If mt = MessageType.SystemDefined Then
                t = GetType(Message.System)
            ElseIf mt = MessageType.WindowClass Then
                t = GetType(Message.WindowClass)
            End If

            ' if t is not nothing that mean we we'll search
            ' type pointed by t for Message Name
            If t IsNot Nothing Then
                ' get array of member info from t
                Dim mi() As MemberInfo = t.FindMembers(MemberTypes.Field, _
                                                       BindingFlags.Public Or BindingFlags.Static, _
                                                       Nothing, Nothing)
                Dim names(mi.Length - 1) As String
                Dim current As Integer = 0

                ' loop over all items
                For i As Integer = 0 To mi.Length - 1
                    ' if member is field
                    If mi(i).MemberType = MemberTypes.Field Then
                        ' then store it in a field info 
                        Dim fi As FieldInfo = CType(mi(i), FieldInfo)

                        ' get its value
                        Dim ret As Object = fi.GetValue(Nothing)

                        If (TypeOf ret Is UInteger AndAlso CUInt(ret) = Code) OrElse _
                           (TypeOf ret Is MessageDef AndAlso CUInt(DirectCast(ret, MessageDef)) = Code) Then
                            names(current) = fi.Name
                            current += 1
                        End If

                    End If
                Next

                ReDim Preserve names(current - 1)
                Return names
            End If

            If mt = MessageType.ApplicationDefined Then
                ' will be implemented after adding Message APIs
                Return Nothing
            End If

            ' if we reach here so mt = MessageType.StringMesage

            ' will implemented after adding Atom APIs

            Return Nothing
        End Function
    End Class

End Namespace